unit NBiometrics;

interface
 uses Windows, SysUtils, NCore, NMedia, NUtils;

 const
  N_MODE_GENERAL = 0;
  N_MODE_DIGITALPERSONA_UAREU = 100;
  N_MODE_BIOMETRIKA_FX2000 = 200;
  N_MODE_BIOMETRIKA_FX3000 = 201;
  N_MODE_KEYTRONIC_SECUREDESKTOP = 300;
  N_MODE_IDENTIX_TOUCHVIEW = 400;
  N_MODE_IDENTIX_DFR2090 = 401;
  N_MODE_PRECISEBIOMETRICS_100CS = 500;
  N_MODE_UPEK_TOUCHCHIP = 600;
  N_MODE_IDENTICATORTECHNOLOGY_DF90 = 700;
  N_MODE_ATMEL_FINGERCHIP = 900;
  N_MODE_BMF_BLP100 = 1000;
  N_MODE_SECUGEN_HAMSTER = 1100;
  N_MODE_CROSSMATCH_VERIFIER300 = 1300;
  N_MODE_NITGEN_FINGKEY_HAMSTER = 1400;
  N_MODE_TESTECH_BIOI = 1500;
  N_MODE_DIGENT_IZZIX = 1600;
  N_MODE_STARTEK_FM200 = 1700;
  N_MODE_FUJITSU_MBF200 = 1800;
  N_MODE_FUTRONIC_FS80 = 1900;
  N_MODE_LIGHTUNING_LTTC500 = 2000;
  N_MODE_TACOMA_CMOS = 2100;

//-------------------------------------
// External functions
//-------------------------------------

procedure NBiometricsGetInfo(var info: TNLibraryInfo);

//-------------------------------------
// Types
//-------------------------------------
type
  TNBiometricType = (
     nbtFacialFeatures = $00000002,
	   nbtFingerprint = $00000008,
	   nbtIris = $00000010,
	   nbtPalmPrint = $00020000,
     nmpUnused = MaxInt
  );

  TNFRecord = class(TObject)
    private
     _handle : Pointer;
    public
     constructor Create(handle: Pointer); overload;
     destructor  Destroy; override;
     property    Handle: Pointer read _handle;

     function MinutiaCount():Integer;
     function Minutia(index: Integer): TNMMinutia;

     function G: Byte;

     function Save: TArrayOfByte; overload;
     function Save(flags: LongWord): TArrayOfByte; overload;

     class function  CreateFromMemory(arr: TArrayOfByte): TNFRecord;
     class procedure Check(arr: TArrayOfByte);
    end;

   TNLRecord = class(TObject)
    private
     _handle: Pointer;
    public
     constructor Create(handle: Pointer); overload;
     constructor Create(flags: Integer); overload;
     destructor  Destroy(); override;
     property    Handle: Pointer read _handle;

     function Clone(): TNLRecord;

     function Quality: Byte;

     function Size: LongWord; overload;
     function Size(flags:Integer): LongWord; overload;
    end;

  TNLTemplate = class(TObject)
    private
      _handle: Pointer;
    public
      constructor Create(handle: Pointer); overload;
      destructor  Destroy(); override;
      property    Handle: Pointer read _handle;

      function Clone(): TNLTemplate;

      function RecordCount: Integer;
      function Size: LongWord; overload;
      function Size(flags:Integer): LongWord; overload;

      function Save: TArrayOfByte; overload;
      function Save(flags: LongWord): TArrayOfByte; overload;

      class function  CreateFromMemory(arr: TArrayOfByte): TNLTemplate;
      class procedure Check(arr: TArrayOfByte);
  end;

  TArrayOfTNFRecord = array of TNFRecord;
  TArrayOfTNLRecord = array of TNLRecord;
  TArrayOfTNLTemplate = array of TNLTemplate;

  TNLExtractor = class
    private
     _handle: Pointer;

     _minIod: Integer;
     _maxIod: Integer;

     _faceConfidenceThreshold: Double;
     _faceQualityThreshold: Byte;
     _maxRecordsInTemplate: Integer;

     _useLiveliness: Boolean;
     _livelinessThreshold: Double;

     _favorLargestFace: Boolean;
     _templateSize: TNleTemplateSize;
     _maxRollAngleDeviation: SmallInt;

     function GetMinIOD(): Integer;
     function GetMaxIOD(): Integer;
     function GetFaceConfidenceThreshold(): Double;
     function GetUseLiveness(): Boolean;
     function GetLivenessThreshold(): Double;
     function GetMaxRecords(): Integer;
     function GetFaceQualityThreshold(): Byte;
     function GetFavorLargestFace(): Boolean;
     function GetTemplateSize: TNleTemplateSize;
     function GetMaxRollAngleDeviation(): SmallInt;

     procedure Initialize;
    public
     constructor Create(); overload;
     destructor  Destroy(); override;
     procedure   Reset();
     property    Handle: Pointer read _handle;

     property  MinIOD: Integer read _minIod;
     property  MaxIOD: Integer read _maxIod;
     property  FaceConfidenceThreshold: Double read _faceConfidenceThreshold;
     property  UseLiveness: Boolean read _useLiveliness;
     property  LivenessThreshold: Double read _livelinessThreshold;
     property  MaxRecordsInTemplate: Integer read _maxRecordsInTemplate;
     property  FaceQualityThreshold: Byte read _faceQualityThreshold;
     property  FavorLargestFace: Boolean read _favorLargestFace;
     property  TemplateSize: TNleTemplateSize read _templateSize;
     property  MaxRollAngleDeviation: SmallInt read _maxRollAngleDeviation;

     procedure SetMinIOD(value: Integer);
     procedure SetMaxIOD(value: Integer);
     procedure SetFaceConfidenceThreshold(value: Double);
     procedure SetUseLiveness(value: Boolean);
     procedure SetLivenessThreshold(value: Double);
     procedure SetFaceQualityThreshold(value: Integer);
     procedure SetMaxRecords(value: Integer);
     procedure SetFavorLargestFace(value: Boolean);
     procedure SetTemplateSize(value: TNleTemplateSize);
     procedure SetMaxRollAngleDeviation(value: SmallInt);

     procedure CopyParameters(destinationExtractor: TNLExtractor);

     function  DetectFaces(image: TNImage): TArrayOfTNleFace;
     function  DetectFacialFeatures(image: TNImage; var face: TNleFace): TNleDetectionDetails;
     function  DetectFace(image: TNImage; var face: TNleFace): Boolean;

     procedure ExtractStart(numOfFrames: Integer);
     function  ExtractNext(image: TNImage; var detectionDetails: TNleDetectionDetails; var baseIndex: Integer; var template: TNLTemplate): TNleExtractionStatus;
     function  Extract(image: TNImage; var template: TNLTemplate; var detectionDetails: TNleDetectionDetails): TNleExtractionStatus;
     function  ExtractUsingDetails(image: TNImage; var detectionDetails: TNleDetectionDetails; var template: TNLTemplate): TNleExtractionStatus;
     function  Generalize(templates: TArrayOfTNLTemplate; var baseIndex: Integer; var generalizedTemplate: TNLTemplate): TNleExtractionStatus;
     function  Compress(templateSrc: TNLTemplate; dstTemplateSize: TNleTemplateSize): TNLTemplate;
    end;

  TNFExtractor = class
    private
     _handle: Pointer;

     _returnedImage: TNfeReturnedimage;
     _useQuality: boolean;
     _qualityThreshold: Integer;
     _scannerMode: Integer;
     _templateSize: TNfeTemplateSize;
     _generalizationThreshold: Integer;
     _generalizationMaximalRotation: Byte;

     function GetScannerMode: Integer;
     function GetUseQuality: Boolean;
     function GetReturnedImage: TNfeReturnedimage;
     function GetTemplateSize: TNfeTemplateSize;
     function GetQualityThreshold: Integer;
     function GetGeneralizationMaximalRotation: Byte;
     function GetGeneralizationThreshold: Integer;

     procedure Initialize;
    public
     Constructor Create;
     Destructor  Destroy; override;
     procedure   Reset();

     property    Handle: Pointer read _handle;

     property  ReturnedImage: TNfeReturnedimage read _returnedImage;
     property  UseQuality: Boolean read _useQuality;
     property  QualityThreshold: Integer read _qualityThreshold;
     property  ScannerMode: Integer read _scannerMode;
     property  TemplateSize: TNfeTemplateSize read _templateSize;
     property  GeneralizationThreshold: Integer read _generalizationThreshold;
     property  GeneralizationMaximalRotation: Byte read _generalizationMaximalRotation;

     procedure SetScannerMode(mode: Integer);
     procedure SetUseQuality(value: Boolean);
     procedure SetReturnedImage(value: TNfeReturnedimage);
     procedure SetTemplateSize(value: TNfeTemplateSize);
     procedure SetQualityThreshold(value: Integer);
     procedure SetGeneralizationMaximalRotation(value: Byte);
     procedure SetGeneralizationThreshold(value: Integer);

     procedure CopyParameters(destinationExtractor: TNFExtractor);

     function  Extract(image: TNImage; position, impression: Integer; var template: TNFRecord): TNfeExtractionStatus;
     function  Generalize(templates: TArrayOfTNFRecord; var baseTemplateIndex: Integer; var extractionStatus: TNfeExtractionStatus): TNFRecord;
    end;

  TNMatcher = class(TObject)
   private
    _handle: Pointer;

    _matchingThreshold: Integer;

    _fingersMode: Integer;
    _fingersMaximalRotation: Integer;
    _fingersMatchingSpeed: TNMSpeed;

    _facesMatchingSpeed: TNMSpeed;

    function GetMatchingThreshold(): Integer;
    function GetFingersMode: Integer;
    function GetFingersMaximalRotation: Byte;
    function GetFingersMatchingSpeed: TNMSpeed;
    function GetFacesMatchingSpeed: TNMSpeed;

    procedure Initialize;
   public
    Constructor Create(); overload;
    Destructor  Destroy; override;
    procedure   Reset();
    property    Handle: Pointer read _handle;

    property  MatchingThreshold: Integer read _matchingThreshold;

    property  FingersMaximalRotation: Integer read _fingersMaximalRotation;
    property  FingersMode: Integer read _fingersMode;
    property  FingersMatchingSpeed: TNMSpeed read _fingersMatchingSpeed;

    property  FacesMatchingSpeed: TNMSpeed read _facesMatchingSpeed;

    procedure SetMatchingThreshold(value: Integer);

    procedure SetFingersMaximalRotation(value: Byte);
    procedure SetFingersMode(value: Integer);
    procedure SetFingersMatchingSpeed(value: TNMSpeed);

    procedure SetFacesMatchingSpeed(value: TNMSpeed);

    procedure CopyParameters(destMatcher: TNMatcher);

    procedure IdentifyStart(template: TArrayOfByte);
    function  IdentifyNext(template: TArrayOfByte): LongInt;
    procedure IdentifyEnd;

    function Verify(template1: TArrayOfByte; template2: TArrayOfByte): LongInt;
  end;

implementation

//-------------------------------------
// Constants
//-------------------------------------

const
  dllName = 'NBiometrics.dll';

  NLEP_MIN_IOD                   = 10101;
  NLEP_MAX_IOD                   = 10102;
  NLEP_FACE_CONFIDENCE_THRESHOLD = 10103;
  NLEP_FAVOR_LARGEST_FACE        = 10104;
  NLEP_MAX_ROLL_ANGLE_DEVIATION  = 10105;
  NLEP_FACE_QUALITY_THRESHOLD    = 10350;
  NLEP_TEMPLATE_SIZE             = 10360;
  NLEP_USE_LIVENESS_CHECK        = 10402;
  NLEP_LIVENESS_THRESHOLD        = 10403;
  NLEP_MAX_RECORDS_PER_TEMPLATE  = 10408;

  NFEP_TEMPLATE_SIZE             = 100;
  NFEP_RETURNED_IMAGE            = 190;
  NFEP_GENERALIZATION_THRESHOLD  = 300;
  NFEP_GENERALIZATION_MAXIMAL_ROTATION = 301;
  NFEP_MODE                      = 1000;
  NFEP_USE_QUALITY               = 900;
  NFEP_QUALITY_THRESHOLD         = 910;

  NMP_MATCHING_THRESHOLD = 100;

  NMP_FINGERS_MATCHER_BASE       = 3536;
  NMP_FINGERS_MAXIMAL_ROTATION   = NMP_FINGERS_MATCHER_BASE + 201;
  NMP_FINGERS_MATCHING_SPEED     = NMP_FINGERS_MATCHER_BASE + 220;
  NMP_FINGERS_MODE               = NMP_FINGERS_MATCHER_BASE + 1000;

  NMP_FACES_MATCHER_BASE   = 11536;
  NMP_FACES_MATCHING_SPEED = NMP_FACES_MATCHER_BASE + 1;

//-------------------------------------
// External functions (from dll)
//-------------------------------------

{$ifdef ver210}
function  NBiometricsGetInfoInternal(var info: TNLibraryInfo): Integer stdcall; external dllName name 'NBiometricsGetInfoW';
{$else}
function  NBiometricsGetInfoInternal(var info: TNLibraryInfo): Integer stdcall; external dllName name 'NBiometricsGetInfoA';
{$endif}

function  NleExtractNextEx(hExtractor: Pointer; hImage: Pointer; var pDetectionDetails: TNleDetectionDetails; var baseFrameIndex: Integer; var template: Pointer; var pStatus: TNleExtractionStatus): Integer stdcall; external dllName;
function  NleCreate(var hExtractor: Pointer): Integer; stdcall; external dllName;
function  NleDetectFace(hExtractor: Pointer; hImage: Pointer; var pDetected: Integer; var pFace: TNleFace): Integer stdcall; external dllName;
function  NleDetectFaces(hExtractor: Pointer; hImage: Pointer; var pFaceCount: Integer; var pArFaces: Pointer): Integer stdcall; external dllName;
function  NleDetectFacialFeatures(hExtractor: Pointer; hImage: Pointer; var pFace: TNleFace; var pDetDetails: TNleDetectionDetails): Integer stdcall; external dllName;
function  NleExtractStart(hExtractor: Pointer; durationInFrames: Integer): Integer stdcall; external dllName;
function  NleExtract(hExtractor: Pointer; hImage: Pointer; var pDetectionDetails: TNleDetectionDetails; var extrStatus: TNleExtractionStatus; template: Pointer): Integer stdcall; external dllName;
function  NleCompress(hExtractor: Pointer; firstTemplate: Pointer; var secondTemplate : Pointer): Integer stdcall; external dllName; 
function  NleCompressEx(firstTemplate: Pointer; templateSize: TNleTemplateSize; var secondTemplate: Pointer): Integer stdcall; external dllName;
function  NleExtractUsingDetails(hExtractor: Pointer; hImage: Pointer; var detDetails: TNleDetectionDetails; var extrStatus: TNleExtractionStatus; var template: Pointer): Integer stdcall; external dllName;
function  NleGeneralizeEx(HExtractor: Pointer; templateCount: LongInt; arTemplates: Pointer; var extractionStatus: TNleExtractionStatus; var baseTemplateIndex: Integer; var resultTemplate: Pointer): Integer stdcall; external dllName;

function  NfeCreate(var pHExtractor: Pointer): Integer stdcall; external dllName;
function  NfeExtract(pHExtractor: Pointer; hImage: Pointer; position: Integer; impressionType: Integer; var extractionStatus: TNfeExtractionStatus; var pHRecord: Pointer): Integer stdcall; external dllName;
function  NfeGeneralizeEx(hExtractor: Pointer; recordCount: LongInt; records: Pointer; var extractionStatus: TNfeExtractionStatus; var pBaseTemplateIndex: LongInt;  var pHRecord: Pointer): Integer stdcall; external dllName;
function  NfeGetMaxTemplateSize(hExtractor: Pointer; var pSize: LongWord): Integer stdcall; external dllName;

function  NLRecordCreate(flags: Integer; var pHRecord: Pointer): Integer stdcall; external dllName;
function  NLRecordGetQuality(hRecord: Pointer; var pValue: Byte): Integer stdcall; external dllName;
function  NLRecordGetSize(hRecord: Pointer; flags: Integer; var pSize: LongWord): Integer stdcall; external dllName;

function  NLTemplateCreate(var pTemplate: Pointer): Integer stdcall; external dllName;
function  NLTemplateGetSize(hTemplate: Pointer;  flags: LongWord; var pSize: LongWord): Integer stdcall; external dllName;
function  NLTemplateSaveToMemory(hTemplate: Pointer; buffer: Pointer; bufferSize: LongWord; flags: Integer; var pSize: LongWord): Integer stdcall; external dllName;
function  NLTemplateGetRecordCount(hTemplate: Pointer; var pValue: LongInt): Integer stdcall; external dllName;
function  NLTemplateCreateFromMemory(hBuffer: Pointer; bufferSize: LongWord; flags: LongWord; var pSize: LongWord; var hTemplate: Pointer): Integer stdcall; external dllName;
function  NLTemplateCheck(hBuffer: Pointer; bufferSize: LongWord): Integer stdcall; external dllName;

function  NFRecordGetMinutiaCount(hRecord: Pointer; var pValue: LongInt): Integer stdcall; external dllName;
function  NFRecordGetMinutia(hRecord: Pointer; index: LongInt; var pValue: TNMMinutia):  Integer stdcall; external dllName;
function  NFRecordGetSize(hRecord: Pointer; flags: LongWord; var pSize: LongInt): Integer stdcall; external dllName;
function  NFRecordSaveToMemory(hRecord: Pointer; buffer: Pointer; size: LongInt; flags: LongWord; var pSize: LongInt): Integer stdcall; external dllName;
function  NFRecordGetG(hRecord: Pointer; var pValue : Byte): Integer stdcall; external dllName;
function  NFRecordCreateFromMemory(buffer: Pointer;  size: LongInt; flags: LongWord; recordInfo: Pointer; var hRecord: Pointer): Integer stdcall; external dllName;
function  NFRecordCheck(hBuffer: Pointer; bufferSize: LongWord): Integer stdcall; external dllName;

function  NMCreate(var pHMatcher: Pointer): Integer stdcall; external dllName;
function  NMIdentifyStart(hMatcher: Pointer; pTempate: Pointer; templateSize: LongWord; ppMatchDetails: Pointer): Integer stdcall; external dllName;
function  NMIdentifyNext(hMatcher: Pointer; pTemplate: Pointer; templateSize: LongWord; ppMatchDetails: Pointer; var pScore: LongInt): Integer stdcall; external dllName;
function  NMIdentifyEnd(hMatcher: Pointer): Integer stdcall; external dllName;
function  NMMatchDetailsFree(MatchDetailsPointer: Pointer): Integer stdcall;external dllName;
function  NMVerify(hMatcher: Pointer; template1: Pointer; template1Size: LongWord; tempalte2: Pointer; template2Size: LongWord; ppMatchDetails: Pointer; var pScore: LongInt): Integer stdcall; external dllName;

//-------------------------------------
// Misc methods
//-------------------------------------

procedure NBiometricsGetInfo(var info: TNLibraryInfo);
 var res: Integer;
begin
 res := NBiometricsGetInfoInternal(info);
 NCheck(res);
end;

//-------------------------------------
// TNLExtractor class methods
//-------------------------------------

constructor TNLExtractor.Create();
 var res:Integer;
begin
 inherited Create;
 res := NleCreate(_handle);
 NCheck(res);
 Initialize;
end;

destructor TNLExtractor.Destroy();
begin
 NObjectFree(_handle);
 inherited;
end;

procedure TNLExtractor.Initialize;
begin
 _minIod := GetMinIOD;
 _maxIod := GetMaxIOD;
 _faceConfidenceThreshold := GetFaceConfidenceThreshold;
 _livelinessThreshold := GetLivenessThreshold;
 _useLiveliness := GetUseLiveness;
 _maxRecordsInTemplate := GetMaxRecords;
 _faceQualityThreshold := GetFaceQualityThreshold;
 _templateSize := GetTemplateSize();
 _maxRollAngleDeviation := GetMaxRollAngleDeviation;
 _favorLargestFace := GetFavorLargestFace;
end;

procedure TNLExtractor.Reset();
begin
 NObjectReset(_handle);
 Initialize;
end;

function TNLExtractor.DetectFaces(image: TNImage): TArrayOfTNleFace;
 var res: Integer;
     addressOfArray: Pointer;
     faceCount: Integer;
     pArFaces: TArrayOfTNleFace;
begin
  res := NleDetectFaces(_handle, image.Handle, faceCount, addressOfArray);
  NCheck(res);
  if (faceCount > 0) then
  begin
   SetLength(pArFaces, faceCount);
   CopyMemory(@(pArFaces[0]), addressOfArray, SizeOf(TNleFace) * faceCount);
   NFree(addressOfArray);
  end;
  Result := pArFaces;
end;

function TNLExtractor.DetectFace(image: TNImage; var face: TNleFace): Boolean;
 var res, tmpInteger: Integer;
begin
 res := NleDetectFace(_handle, image.Handle, tmpInteger, face);
 NCheck(res);
 if (tmpInteger = 1) then Result := true
                     else Result := false;
end;

function TNLExtractor.DetectFacialFeatures(image: TNImage; var face: TNleFace): TNleDetectionDetails;
 var res: Integer;
     details: TNleDetectionDetails;
begin
 res := NleDetectFacialFeatures(_handle, image.Handle, face, details);
 NCheck(res);
 Result := details;
end;

function TNLExtractor.Extract(image: TNImage; var template: TNLTemplate; var detectionDetails: TNleDetectionDetails): TNleExtractionStatus;
 var res: Integer;
     tmpTemplate: Pointer;
     extrStatus: TNleExtractionStatus;
     vDetectionDetails: TNleDetectionDetails;
begin
 tmpTemplate := nil;
 res := NleExtract(_handle, image.Handle, vDetectionDetails, extrStatus, @tmpTemplate);
 NCheck(res);
 detectionDetails := vDetectionDetails;
 if (extrStatus = nleesTemplateCreated) Then
 Begin
  template := TNLTemplate.Create(tmpTemplate);
 End;
 Result := extrStatus;
end;

function TNLExtractor.ExtractUsingDetails(image: TNImage; var detectionDetails: TNleDetectionDetails; var template: TNLTemplate): TNleExtractionStatus;
 var res: Integer;
     tmpTemplate: Pointer;
     extrStatus: TNleExtractionStatus;
begin
 tmpTemplate := nil;
 res := NleExtractUsingDetails(_handle, image.Handle, detectionDetails, extrStatus, tmpTemplate);
 NCheck(res);
 if (extrStatus = nleesTemplateCreated) Then
 Begin
  template := TNLTemplate.Create(tmpTemplate);
 End;
 Result := extrStatus;
end;

function TNLExtractor.Generalize(templates: TArrayOfTNLTemplate; var baseIndex: Integer; var generalizedTemplate: TNLTemplate): TNleExtractionStatus;
 var res, i: Integer;
     tmpPointer: Pointer;
     arrayOfPointers: TArrayOfPointer;
     extractionStatus: TNleExtractionStatus;
begin
 SetLength(arrayOfPointers, Length(templates));
 for i := 0 to Length(templates) - 1 do
  begin
   arrayOfPointers[i] := templates[i].Handle;
  end;

 res := NleGeneralizeEx(_handle, Length(arrayOfPointers), @(arrayOfPointers[0]), extractionStatus, baseIndex, tmpPointer);
 NCheck(res);
 if (tmpPointer <> nil) then
  generalizedTemplate := TNLTemplate.Create(tmpPointer)
 else
  generalizedTemplate := nil;
 Result := extractionStatus;
end;

function TNLExtractor.Compress(templateSrc: TNLTemplate; dstTemplateSize: TNleTemplateSize): TNLTemplate;
 var res: Integer;
     tmpPointer: Pointer;
begin
 res := NleCompressEx(templateSrc.Handle, dstTemplateSize, tmpPointer);
 NCheck(res);
 if (tmpPointer <> nil) then
  Result := TNLTemplate.Create(tmpPointer)
 else
  Result := nil;
end;

procedure TNLExtractor.CopyParameters(destinationExtractor: TNLExtractor);
begin
 NObjectCopyParameters(destinationExtractor._handle, _handle);
 destinationExtractor.Initialize;
end;

procedure TNLExtractor.ExtractStart(NumOfFrames: Integer);
 var res: Integer;
begin
 res := NleExtractStart(_handle, NumOfFrames);
 NCheck(res);
end;

function TNLExtractor.ExtractNext(image: TNImage; var detectionDetails: TNleDetectionDetails; var baseIndex: Integer; var template: TNLTemplate): TNleExtractionStatus;
 var res: Integer;
     tmpTemplate: Pointer;
     extrStatus: TNleExtractionStatus;
begin
 res := NleExtractNextEx(_handle, image.Handle, detectionDetails, baseIndex, tmpTemplate, extrStatus);
 NCheck(res);
 if (extrStatus = nleesTemplateCreated) then
  template := TNLTemplate.Create(tmpTemplate);
 Result := extrStatus;
end;

function TNLExtractor.GetTemplateSize: TNleTemplateSize;
 var tmp: Integer;
begin
 GetParameter(_handle, NLEP_MAX_RECORDS_PER_TEMPLATE, tmp);
 Result := TNleTemplateSize(tmp);
end;

procedure TNLExtractor.SetTemplateSize(value: TNleTemplateSize);
 var val: Integer;
begin
 val := Integer(value);
 SetParameter(_handle, NLEP_MAX_RECORDS_PER_TEMPLATE, val);
 _templateSize := value;
end;

procedure TNLExtractor.SetMaxRollAngleDeviation(value: SmallInt);
 var res: SmallInt;
begin
 res := value;
 SetParameter(_handle, NLEP_MAX_ROLL_ANGLE_DEVIATION, res);
 _maxRollAngleDeviation :=  value;
end;

function TNLExtractor.GetMaxRollAngleDeviation: SmallInt;
 var tmp: SmallInt;
begin
 GetParameter(_handle, NLEP_MAX_ROLL_ANGLE_DEVIATION, tmp);
 Result := tmp;
end;

procedure TNLExtractor.SetFavorLargestFace(value: Boolean);
begin
 SetParameter(Self, NLEP_FAVOR_LARGEST_FACE, value);
 _favorLargestFace := value;
end;

function TNLExtractor.GetFavorLargestFace(): Boolean;
 var tmp: Boolean;
begin
 GetParameter(_handle, NLEP_FAVOR_LARGEST_FACE, tmp);
 Result := tmp;
end;

procedure TNLExtractor.SetMaxRecords(value: Integer);
begin
 SetParameter(_handle, NLEP_MAX_RECORDS_PER_TEMPLATE, value);
 _maxRecordsInTemplate :=  value;
end;

function TNLExtractor.GetMaxRecords: Integer;
 var tmp: Integer;
begin
 GetParameter(_handle, NLEP_MAX_RECORDS_PER_TEMPLATE, tmp);
 Result := tmp;
end;

function TNLExtractor.GetFaceQualityThreshold: Byte;
 var tmp: Byte;
begin
 GetParameter(_handle, NLEP_FACE_QUALITY_THRESHOLD, tmp);
 Result := tmp;
end;

procedure TNLExtractor.SetFaceQualityThreshold(value: Integer);
begin
 SetParameter(_handle, NLEP_FACE_QUALITY_THRESHOLD, value);
 _faceQualityThreshold :=  value;
end;

procedure TNLExtractor.SetMinIOD(value: Integer);
begin
 SetParameter(_handle, NLEP_MIN_IOD, value);
 _minIod :=  value;
end;

function TNLExtractor.GetMinIOD(): Integer;
 var tmp: Integer;
begin
 GetParameter(_handle, NLEP_MIN_IOD, tmp);
 Result := tmp;
end;

procedure TNLExtractor.SetUseLiveness(value: Boolean);
begin
 SetParameter(_handle, NLEP_USE_LIVENESS_CHECK, value);
 _useLiveliness := value;
end;

function TNLExtractor.GetUseLiveness(): Boolean;
 var tmp: Boolean;
begin
 GetParameter(_handle, NLEP_USE_LIVENESS_CHECK, tmp);
 Result := tmp;
end;

procedure TNLExtractor.SetMaxIOD(value: Integer);
begin
 SetParameter(_handle, NLEP_MAX_IOD, value);
 _maxIod :=  value;
end;

function TNLExtractor.GetMaxIOD(): Integer;
 var tmp: Integer;
begin
 GetParameter(_handle, NLEP_MAX_IOD, tmp);
 Result := tmp;
end;

procedure TNLExtractor.SetFaceConfidenceThreshold(value: Double);
begin
 SetParameter(_handle, NLEP_FACE_CONFIDENCE_THRESHOLD, value);
 _faceConfidenceThreshold := value;
end;

function TNLExtractor.GetFaceConfidenceThreshold(): Double;
 var tmp: Double;
begin
 GetParameter(_handle, NLEP_FACE_CONFIDENCE_THRESHOLD, tmp);
 Result := tmp;
end;

procedure TNLExtractor.SetLivenessThreshold(value: Double);
begin
 SetParameter(_handle, NLEP_LIVENESS_THRESHOLD, value);
 _livelinessThreshold := value;
end;

function TNLExtractor.GetLivenessThreshold(): Double;
 var tmp: Double;
begin
 GetParameter(_handle, NLEP_LIVENESS_THRESHOLD, tmp);
 Result := tmp;
end;

//-------------------------------------
// TNFExtractor class methods
//-------------------------------------

constructor TNFExtractor.Create();
 var res:Integer;
begin
 res := NfeCreate(_handle);
 NCheck(res);
 Initialize;
end;

destructor TNFExtractor.Destroy();
begin
 NObjectFree(_handle);
 inherited;
end;

procedure TNFExtractor.CopyParameters(destinationExtractor: TNFExtractor);
begin
 NObjectCopyParameters(destinationExtractor._handle, _handle);
 destinationExtractor.Initialize;
end;

procedure TNFExtractor.Initialize;
begin
 _returnedImage := TNfeReturnedImage(GetReturnedImage);
 _useQuality := GetUseQuality;
 _qualityThreshold := GetQualityThreshold;
 _scannerMode := GetScannerMode;
 _templateSize := TNfeTemplateSize(GetTemplateSize);
 _generalizationThreshold := GetGeneralizationThreshold;
 _generalizationMaximalRotation := GetGeneralizationMaximalRotation;
end;

procedure TNFExtractor.Reset();
begin
 NObjectReset(_handle);
 Initialize;
end;

function TNFExtractor.Extract(image: TNImage; position, impression: Integer; var template: TNFRecord): TNfeExtractionStatus;
 var nfRecord: Pointer;
     ret: Integer;
     extractionStatus: TNfeExtractionStatus;
begin
  ret := NfeExtract(_handle, image.Handle, position, impression, extractionStatus, nfRecord);
  NCheck(ret);
  if (nfRecord = nil) Then
    template := nil
  Else
   Begin
    template := TNFRecord.Create(nfRecord);
   End;
  Result := extractionStatus;
end;

function TNFExtractor.Generalize(templates: TArrayOfTNFRecord; var baseTemplateIndex: Integer; var extractionStatus: TNfeExtractionStatus): TNFRecord;
 var ret, i: Integer;
     nfRecord: Pointer;
     arrayOfPointers: TArrayOfPointer;
begin
 SetLength(arrayOfPointers, Length(templates));
 for i := 0 to Length(templates) - 1 do
  begin
   arrayOfPointers[i] := templates[i].Handle;
  end;

 ret := NfeGeneralizeEx(_handle, Length(arrayOfPointers), arrayOfPointers, extractionStatus, baseTemplateIndex, nfRecord);
 NCheck(ret);
 if (nfRecord <> nil) then
  Result := TNFRecord.Create(nfRecord)
 Else
  Result := nil;
end;

function TNFExtractor.GetScannerMode: Integer;
  var res: Integer;
begin
 GetParameter(_handle, NFEP_MODE, res);
 Result := res;
end;

procedure TNFExtractor.SetScannerMode(mode :Integer);
begin
  SetParameter(_handle, NFEP_MODE, mode);
  _scannerMode := mode;
end;

function TNFExtractor.GetUseQuality: Boolean;
 var res: Boolean;
begin
 GetParameter(_handle, NFEP_USE_QUALITY, res);
 Result := res;
end;

procedure TNFExtractor.SetUseQuality(value: Boolean);
begin
 SetParameter(_handle, NFEP_USE_QUALITY, value);
 _useQuality := value;
end;

function TNFExtractor.GetReturnedImage: TNfeReturnedimage;
 var res: Integer;
begin
 GetParameter(_handle, NFEP_RETURNED_IMAGE, res);
 Result := TNfeReturnedimage(res);
end;

procedure TNFExtractor.SetReturnedImage(value: TNfeReturnedimage);
 var val: Integer;
begin
 val := Integer(value);
 SetParameter(_handle, NFEP_RETURNED_IMAGE, val);
 _returnedImage := value;
end;

function TNFExtractor.GetTemplateSize: TNfeTemplateSize;
 var res: Integer;
begin
 GetParameter(_handle, NFEP_TEMPLATE_SIZE, res);
 Result := TNfeTemplateSize(res);
end;

procedure TNFExtractor.SetTemplateSize(value: TNfeTemplateSize);
  var val: Integer;
begin
 val := Integer(value);
 SetParameter(_handle, NFEP_TEMPLATE_SIZE, val);
 _templateSize := value;
end;

function TNFExtractor.GetQualityThreshold: Integer;
 var res: Byte;
begin
 GetParameter(_handle, NFEP_QUALITY_THRESHOLD, res);
 Result := res;
end;

procedure TNFExtractor.SetQualityThreshold(value: Integer);
  var res: Byte;
begin
 res := value;
 SetParameter(_handle, NFEP_QUALITY_THRESHOLD, res);
 _qualityThreshold := value;
end;

function TNFExtractor.GetGeneralizationMaximalRotation: Byte;
 var res: Byte;
begin
 GetParameter(_handle, NFEP_GENERALIZATION_MAXIMAL_ROTATION, res);
 Result := res;
end;

procedure TNFExtractor.SetGeneralizationMaximalRotation(value: Byte);
  var res: SmallInt;
begin
 res := value;
 SetParameter(_handle, NFEP_GENERALIZATION_MAXIMAL_ROTATION, res);
 _generalizationMaximalRotation := value;
end;

function TNFExtractor.GetGeneralizationThreshold: Integer;
 var res: Integer;
begin
 GetParameter(_handle, NFEP_GENERALIZATION_THRESHOLD, res);
 Result := res;
end;

procedure TNFExtractor.SetGeneralizationThreshold(value: Integer);
begin
 SetParameter(_handle, NFEP_GENERALIZATION_THRESHOLD, value);
 _generalizationThreshold := value;
end;

//-------------------------------------
// NFRecord
//-------------------------------------

constructor TNFRecord.Create(handle: Pointer);
begin
  inherited Create;
  self._handle := handle;
end;

class function TNFRecord.CreateFromMemory(arr: TArrayOfByte): TNFRecord;
  var ptr: Pointer;
      res: Integer;
begin
  res := NFRecordCreateFromMemory(@(arr[0]), Length(arr), 0, nil, ptr);
  NCheck(res);
  if (ptr <> nil) then
  begin
    Result := TNFRecord.Create(ptr);
  end
  else
    Result := nil;
end;

class procedure TNFRecord.Check(arr: TArrayOfByte);
 var res: Integer;
begin
 res :=  NFRecordCheck(@(arr[0]), Length(arr));
 NCheck(res);
end;

destructor TNFRecord.Destroy;
begin
  NObjectFree(_handle);
  inherited;
end;

function TNFRecord.MinutiaCount: Integer;
  var res, minutiaesCount: Integer;
begin
  res := NFRecordGetMinutiaCount(_handle, minutiaesCount);
  NCheck(res);
  Result := minutiaesCount;
end;

function TNFRecord.Minutia(index: Integer): TNMMinutia;
  var res: Integer;
      minutiae: TNMMinutia;
begin
  res := NFRecordGetMinutia(_handle, index, minutiae);
  NCheck(res);
  Result := minutiae;
end;

function TNFRecord.Save: TArrayOfByte;
begin
  Result := Save(0);
end;

function TNFRecord.Save(flags: LongWord): TArrayOfByte;
var res: Integer;
    size, retSize: LongInt;
    recordArray: TArrayOfByte;
begin
  res := NFRecordGetSize(_handle, flags, size);
  NCheck(res);
  SetLength(recordArray, size);
  res := NFRecordSaveToMemory(_handle, @(recordArray[0]), size, flags, retSize );
  NCheck(res);
  Result := recordArray;
end;

function TNFRecord.G: Byte;
  var res: Integer;
      val: Byte;
begin
  res := NFRecordGetG(_handle, val);
  NCheck(res);
  Result := val;
end;

//-------------------------------------
// NLRecord
//-------------------------------------

constructor TNLRecord.Create(flags: Integer);
  var res: Integer;
begin
  inherited Create;
  res := NLRecordCreate(flags, _handle);
  NCheck(res);
end;

constructor TNLRecord.Create(handle: Pointer);
begin
  inherited Create;
  self._handle := handle;
end;

destructor TNLRecord.Destroy();
begin
  NObjectFree(_handle);
  inherited;
end;

function TNLRecord.Clone(): TNLRecord;
  var tmpPointer: Pointer;
begin
  NObjectClone(self._handle, tmpPointer);
  Result := TNLRecord.Create(tmpPointer);
end;

function TNLRecord.Size: LongWord;
begin
  Result := Size(0);
end;

function TNLRecord.Size(flags:Integer): LongWord;
  var res:Integer;
      sz: LongWord;
begin
  res := NLRecordGetSize(_handle, flags, sz);
  NCheck(res);
  Result := sz;
end;

function TNLRecord.Quality(): Byte;
  var res:Integer;
      b: Byte;
begin
  res := NLRecordGetQuality(_handle, b);
  NCheck(res);
  Result := b;
end;

//-------------------------------------
// NLTemplate
//-------------------------------------

class function TNLTemplate.CreateFromMemory(arr: TArrayOfByte): TNLTemplate;
  var res: Integer;
      tmpPointer: Pointer;
      tmpSize: LongWord;
Begin
 res :=  NLTemplateCreateFromMemory(@(arr[0]), Length(arr), 0, tmpSize, tmpPointer);
 NCheck(res);
 if (tmpPointer <> nil) then
    Result := TNLTemplate.Create(tmpPointer)
 else
    Result := nil;
End;

class procedure TNLTemplate.Check(arr: TArrayOfByte);
 var res: Integer;
begin
 res :=  NLTemplateCheck(@(arr[0]), Length(arr));
 NCheck(res);
end;

constructor TNLTemplate.Create(handle: Pointer);
begin
  inherited Create;
  self._handle := handle;
end;

destructor TNLTemplate.Destroy();
begin
  NObjectFree(_handle);
  inherited;
end;

function TNLTemplate.Clone(): TNLTemplate;
  var tmpPointer: Pointer;
begin
  NObjectClone(self._handle, tmpPointer);
  Result := TNLTemplate.Create(tmpPointer);
end;

function TNLTemplate.Size: LongWord;
begin
  Result := Size(0);
end;

function TNLTemplate.Size(flags: Integer): LongWord;
  var res:Integer;
      sz: LongWord;
begin
  res := NLTemplateGetSize(_handle, flags, sz);
  NCheck(res);
  Result := sz;
end;

function TNLTemplate.RecordCount: Integer;
 var res: Integer;
     rc: Integer;
begin
 res := NLTemplateGetRecordCount(_handle, rc);
 NCheck(res);
 Result := rc;
end;

function TNLTemplate.Save: TArrayOfByte;
begin
  Result := Save(0);
end;

function TNLTemplate.Save(flags: LongWord): TArrayOfByte;
  var res: Integer;
      pSize: LongWord;
      arr: TArrayOfByte;
begin
  pSize := Self.Size(0);
  SetLength(arr, pSize);
  res := NLTemplateSaveToMemory(self._handle, @(arr[0]), Length(arr), flags, pSize);
  NCheck(res);
  SetLength(arr, pSize);
  Result := arr;
end;

//-----------------------------------------
// TNMatcher class methods
//-----------------------------------------

procedure TNMatcher.Initialize;
begin
  _matchingThreshold := GetMatchingThreshold;

  _fingersMaximalRotation := GetFingersMaximalRotation;
  _fingersMode := GetFingersMode;
  _fingersMatchingSpeed := GetFingersMatchingSpeed;

  _facesMatchingSpeed := GetFacesMatchingSpeed;
end;

constructor TNMatcher.Create();
begin
   inherited;
   NCheck(NMCreate(_handle));
   Initialize;
end;

destructor TNMatcher.Destroy;
begin
   NObjectFree(_handle);
   inherited;
end;

procedure TNMatcher.Reset();
begin
  NObjectReset(_handle);
  Initialize;
end;

procedure TNMatcher.IdentifyStart(template: TArrayOfByte);
begin
 NCheck(NMIdentifyStart(_handle, @(template[0]), Length(template), nil)); //_identifyMatchingDetailsPointer));
end;

function TNMatcher.IdentifyNext(template: TArrayOfByte): LongInt;
 var res: Integer;
     tmp: LongInt;
begin
 tmp := 0;
 res := NMIdentifyNext(_handle, @(template[0]), Length(template), nil, tmp);
 NCheck(res);
 Result := tmp;
  end;

procedure TNMatcher.IdentifyEnd;
 var res: Integer;
begin
 res := NMIdentifyEnd(_handle);
 NCheck(res);
end;

function TNMatcher.Verify(template1: TArrayOfByte; template2: TArrayOfByte): LongInt;
 var res: Integer;
     tmp: LongInt;
begin
 tmp := 0;
 res := NMVerify(_handle, @(template1[0]), Length(template1), @(template2[0]), Length(template2), nil, tmp);
 NCheck(res);
 Result := tmp;
end;

procedure TNMatcher.CopyParameters(destMatcher: TNMatcher);
begin
 NObjectCopyParameters(destMatcher._handle, _handle);
 Initialize;
end;

function TNMatcher.GetFingersMaximalRotation: Byte;
 var res: ShortInt;
begin
 GetParameter(_handle, NMP_FINGERS_MAXIMAL_ROTATION, res);
 Result := res;
end;

procedure TNMatcher.SetFingersMaximalRotation(value: Byte);
 var res: ShortInt;
begin
 res := value;
 SetParameter(_handle, NMP_FINGERS_MAXIMAL_ROTATION, res);
 _fingersMaximalRotation := value;
end;

function TNMatcher.GetFingersMatchingSpeed : TNMSpeed;
 var res: LongWord;
begin
 GetParameter(_handle, 0, NMP_FINGERS_MATCHING_SPEED, res);
 Result := TNMSpeed(res);
end;

procedure TNMatcher.SetFingersMatchingSpeed(value: TNMSpeed);
  var v: Integer;
begin
 v := Integer(value);
 SetParameter(_handle, NMP_FINGERS_MATCHING_SPEED, v);
 _fingersMatchingSpeed := value;
end;

function TNMatcher.GetFingersMode: Integer;
  var res: Integer;
begin
 GetParameter(_handle, NMP_FINGERS_MODE, res);
 Result := res;
end;

procedure TNMatcher.SetFingersMode(value :Integer);
begin
  SetParameter(_handle, NMP_FINGERS_MODE, value);
  _fingersMode := value;
end;

function TNMatcher.GetFacesMatchingSpeed : TNMSpeed;
 var res: LongWord;
begin
 GetParameter(_handle, 0, NMP_FACES_MATCHING_SPEED, res);
 Result := TNMSpeed(res);
end;

procedure TNMatcher.SetFacesMatchingSpeed(value: TNMSpeed);
  var v: Integer;
begin
 v := Integer(value);
 SetParameter(_handle, NMP_FACES_MATCHING_SPEED, v);
 _facesMatchingSpeed := value;
end;

function TNMatcher.GetMatchingThreshold: Integer;
 var res: Integer;
begin
 GetParameter(_handle, NMP_MATCHING_THRESHOLD, res);
 Result := res;
end;

procedure TNMatcher.SetMatchingThreshold(value: Integer);
begin
 SetParameter(_handle, NMP_MATCHING_THRESHOLD, value);
 _matchingThreshold := value;
end;

end.
